home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 365_02 / unix.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  5KB  |  223 lines

  1. /* unix.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the unix-specific versions the ttyread() functions.
  12.  * There are actually three versions of ttyread() defined here, because
  13.  * BSD, SysV, and V7 all need quite different implementations.
  14.  */
  15.  
  16. #include "config.h"
  17. #if ANY_UNIX
  18. # include "vi.h"
  19.  
  20. # if BSD
  21. /* For BSD, we use select() to wait for characters to become available,
  22.  * and then do a read() to actually get the characters.  We also try to
  23.  * handle SIGWINCH -- if the signal arrives during the select() call, then
  24.  * we adjust the o_columns and o_lines variables, and fake a control-L.
  25.  */
  26. #  include <sys/types.h>
  27. #  include <sys/time.h>
  28. int ttyread(buf, len, time)
  29.     char    *buf;    /* where to store the gotten characters */
  30.     int    len;    /* maximum number of characters to read */
  31.     int    time;    /* maximum time to allow for reading */
  32. {
  33.     fd_set    rd;    /* the file descriptors that we want to read from */
  34.     static    tty;    /* 'y' if reading from tty, or 'n' if not a tty */
  35.     int    i;
  36.     struct timeval t;
  37.     struct timeval *tp;
  38.  
  39.  
  40.     /* do we know whether this is a tty or not? */
  41.     if (!tty)
  42.     {
  43.         tty = (isatty(0) ? 'y' : 'n');
  44.     }
  45.  
  46.     /* compute the timeout value */
  47.     if (time)
  48.     {
  49.         t.tv_sec = time / 10;
  50.         t.tv_usec = (time % 10) * 100000L;
  51.         tp = &t;
  52.     }
  53.     else
  54.     {
  55.         tp = (struct timeval *)0;
  56.     }
  57.  
  58.     /* loop until we get characters or a definite EOF */
  59.     for (;;)
  60.     {
  61.         if (tty == 'y')
  62.         {
  63.             /* wait until timeout or characters are available */
  64.             FD_ZERO(&rd);
  65.             FD_SET(0, &rd);
  66.             i = select(1, &rd, (fd_set *)0, (fd_set *)0, tp);
  67.         }
  68.         else
  69.         {
  70.             /* if reading from a file or pipe, never timeout!
  71.              * (This also affects the way that EOF is detected)
  72.              */
  73.             i = 1;
  74.         }
  75.     
  76.         /* react accordingly... */
  77.         switch (i)
  78.         {
  79.           case -1:    /* assume we got an EINTR because of SIGWINCH */
  80.             if (*o_lines != LINES || *o_columns != COLS)
  81.             {
  82.                 *o_lines = LINES;
  83.                 *o_columns = COLS;
  84. #ifndef CRUNCH
  85.                 if (!wset)
  86.                 {
  87.                     *o_window = LINES - 1;
  88.                 }
  89. #endif
  90.                 if (mode != MODE_EX)
  91.                 {
  92.                     /* pretend the user hit ^L */
  93.                     *buf = ctrl('L');
  94.                     return 1;
  95.                 }
  96.             }
  97.             break;
  98.     
  99.           case 0:    /* timeout */
  100.             return 0;
  101.     
  102.           default:    /* characters available */
  103.             return read(0, buf, len);
  104.         }
  105.     }
  106. }
  107. # else
  108.  
  109. # if M_SYSV
  110. /* For System-V or Coherent, we use VMIN/VTIME to implement the timeout.
  111.  * For no timeout, VMIN should be 1 and VTIME should be 0; for timeout,
  112.  * VMIN should be 0 and VTIME should be the timeout value.
  113.  */
  114. #  include <termio.h>
  115. int ttyread(buf, len, time)
  116.     char    *buf;    /* where to store the gotten characters */
  117.     int    len;    /* maximum number of characters to read */
  118.     int    time;    /* maximum time to allow for reading */
  119. {
  120.     struct termio tio;
  121.     int    bytes;    /* number of bytes actually read */
  122.  
  123.     /* arrange for timeout */
  124.     ioctl(0, TCGETA, &tio);
  125.     if (time)
  126.     {
  127.         tio.c_cc[VMIN] = 0;
  128.         tio.c_cc[VTIME] = time;
  129.     }
  130.     else
  131.     {
  132.         tio.c_cc[VMIN] = 1;
  133.         tio.c_cc[VTIME] = 0;
  134.     }
  135.     ioctl(0, TCSETA, &tio);
  136.  
  137.     /* Perform the read.  Loop if EINTR error happens */
  138.     while ((bytes = read(0, buf, len)) < 0)
  139.     {
  140.         /* probably EINTR error because a SIGWINCH was received */
  141.         if (*o_lines != LINES || *o_columns != COLS)
  142.         {
  143.             *o_lines = LINES;
  144.             *o_columns = COLS;
  145. #ifndef CRUNCH
  146.             if (!wset)
  147.             {
  148.                 *o_window = LINES - 1;
  149.             }
  150. #endif
  151.             if (mode != MODE_EX)
  152.             {
  153.                 /* pretend the user hit ^L */
  154.                 *buf = ctrl('L');
  155.                 return 1;
  156.             }
  157.         }
  158.     }
  159.  
  160.     /* return the number of bytes read */
  161.     return bytes;
  162.  
  163.     /* NOTE: The terminal may be left in a timeout-mode after this function
  164.      * returns.  This shouldn't be a problem since Elvis *NEVER* tries to
  165.      * read from the keyboard except through this function.
  166.      */
  167. }
  168.  
  169. # else /* any other version of UNIX, assume it is V7 compatible */
  170.  
  171. /* For V7 UNIX (including Minix) we set an alarm() before doing a blocking
  172.  * read(), and assume that the SIGALRM signal will cause the read() function
  173.  * to give up.
  174.  */
  175.  
  176. #include <setjmp.h>
  177.  
  178. static jmp_buf env;
  179.  
  180. /*ARGSUSED*/
  181. int dummy(signo)
  182.     int    signo;
  183. {
  184.     longjmp(env, 1);
  185. }
  186. int ttyread(buf, len, time)
  187.     char    *buf;    /* where to store the gotten characters */
  188.     int    len;    /* maximum number of characters to read */
  189.     int    time;    /* maximum time to allow for reading */
  190. {
  191.     /* arrange for timeout */
  192. #if __GNUC__
  193.     signal(SIGALRM, (void (*)()) dummy);
  194. #else
  195.     signal(SIGALRM, dummy);
  196. #endif
  197.     alarm(time);
  198.  
  199.     /* perform the blocking read */
  200.     if (setjmp(env) == 0)
  201.     {
  202.         len = read(0, buf, len);
  203.     }
  204.     else /* I guess we timed out */
  205.     {
  206.         len = 0;
  207.     }
  208.  
  209.     /* cancel the alarm */
  210.     signal(SIGALRM, dummy); /* <-- to work around a bug in Minix */
  211.     alarm(0);
  212.  
  213.     /* return the number of bytes read */
  214.     if (len < 0)
  215.         len = 0;
  216.     return len;
  217. }
  218.  
  219. # endif /* !(M_SYSV || COHERENT) */
  220. # endif /* !BSD */
  221.  
  222. #endif /* ANY_UNIX */
  223.